#ifndef __POOL_H__
#define __POOL_H__

#include "pthread.h"
#include <queue>

namespace Framework
{

    template<class T> class Pool
    {
        public:
            Pool()
            {
                pthread_mutex_init(&m_mutex, 0);
                pthread_cond_init(&m_cond, 0);
            }

            virtual ~Pool()
            {
                pthread_mutex_lock(&m_mutex);

                while(m_qData.size())
                {
                    m_qData.pop();
                }

                pthread_mutex_unlock(&m_mutex);

                pthread_mutex_destroy(&m_mutex);
                pthread_cond_destroy(&m_cond);
            }

        public:
            size_t size()
            {
                pthread_mutex_lock(&m_mutex);
                size_t result = m_qData.size();
                pthread_mutex_unlock(&m_mutex);

                return result;
            }

            void push(T item)
            {
                pthread_mutex_lock(&m_mutex);

                m_qData.push(item);
                pthread_cond_broadcast(&m_cond);

                pthread_mutex_unlock(&m_mutex);
            }

            T pop(int _iTimeoutMS = 0)
            {
                pthread_mutex_lock(&m_mutex);

                if(m_qData.size() == 0)
                {
                    if(_iTimeoutMS == 0)
                    {
                        pthread_cond_wait(&m_cond, &m_mutex);
                    }
                    else
                    {
                        struct timespec timeout;
                        timeout.tv_sec = _iTimeoutMS / 1000;
                        timeout.tv_nsec = (_iTimeoutMS - (timeout.tv_sec * 1000)) * 1000000;

                        pthread_cond_timedwait(&m_cond, &m_mutex, &timeout);
                    }
                }

                T item = m_qData.front();
                m_qData.pop();

                pthread_mutex_unlock(&m_mutex);

                return item;
            }

        private:
            std::queue<T> m_qData;
            pthread_mutex_t m_mutex;
            pthread_cond_t m_cond;
    };

}

#endif
